#include "commandparser.h"
#include <QDataStream>
#include <QTextStream>
#include <QList>
#include <QtEndian>
#include <QDebug>

#include "../core/core.h"

CommandParser::CommandParser(QObject *parent) :
    QObject(parent)
{
	QDataStream outOk(&m_okBlock, QIODevice::WriteOnly);
	outOk.setVersion(QDataStream::Qt_4_7);
	outOk << (quint32)0;
	outOk.writeRawData( "OK\n", strlen("OK\n") );
	outOk.device()->seek(0);
	outOk << (quint32)(m_okBlock.size() - sizeof(quint32));

	QDataStream outFail(&m_failBlock, QIODevice::WriteOnly);
	outFail.setVersion(QDataStream::Qt_4_7);
	outFail << (quint32)0;
	outFail.writeRawData( "FAIL\n", strlen("FAIL\n") );
	outFail.device()->seek(0);
	outFail << (quint32)(m_failBlock.size() - sizeof(quint32));

	QDataStream outLogin(&m_loginBlock, QIODevice::WriteOnly);
	outLogin.setVersion(QDataStream::Qt_4_7);
	outLogin << (quint32)0;
	outLogin.writeRawData( "LOGIN\n", strlen("LOGIN\n") );
	outLogin.device()->seek(0);
	outLogin << (quint32)(m_loginBlock.size() - sizeof(quint32));

}


void CommandParser::decodeData(ClientSocket *socket, QByteArray data){
	QTextStream inText(data);

	QString command = inText.readLine();
	if( "USERLOGIN" == command ){
		logMeIn( socket, data );
		return;
	}else if( "ADDLOGIN" == command ){
		addLogin( socket, data );
		return;
	}else if( "CHANGEPASSWORD" == command ){
		changePassword( socket, data );
		return;
	}else if( "GETCHANNELS" == command ){
		getChannels( socket, data );
		return;
	}else if( "GETNEWS" == command ){
		getNews( socket, data );
		return;
	}else if( "ADDCHANNEL" == command ){
		addChannel( socket, data );
		return;
	}else if( "UPDATENEWS" == command ){
		updateNews( socket, data );
		return;
	}
}

void CommandParser::logMeIn(ClientSocket *socket, QByteArray &data){
	QTextStream inText(data);

	inText.readLine(); //skip first line
	QString login = inText.readLine(); //take login
	QString password = inText.readLine(); //take password

	IDatabase *db = qobject_cast<IDatabase*>(Core::instance()->database());
	if( db ){
		quint64 id = db->checkLogin( login, password );
		if( id ){
			socket->setUserId( id );
			socket->setAutorized( true );
			socket->write( m_okBlock );
			return;
		}

	}

	socket->write( m_failBlock );
	socket->disconnectFromHost();
}

void CommandParser::addLogin(ClientSocket *socket, QByteArray &data){
	QTextStream inText(data);

	inText.readLine(); //skip first line
	QString login = inText.readLine(); //take login
	QString password = inText.readLine(); //take password

	IDatabase *db = qobject_cast<IDatabase*>(Core::instance()->database());

	if( db ){
		bool flag = db->addLogin( login, password );
		if( flag ){
			socket->write( m_okBlock );
			return;
		}
	}

	socket->write( m_failBlock );
}

void CommandParser::changePassword(ClientSocket *socket, QByteArray &data){
	if( !socket->isAuthorized() ){
		socket->write( m_loginBlock );
		return;
	}

	QTextStream inText(data);

	inText.readLine(); //skip first line

	QString oldPassword = inText.readLine(); //take oldPassword
	QString newPassword = inText.readLine(); //take newPassword

	quint64 id = socket->userId();

	IDatabase *db = qobject_cast<IDatabase*>(Core::instance()->database());

	if( db ){
		bool flag = db->changePassword( id, oldPassword, newPassword );
		if( flag ){
			socket->write( m_okBlock );
			return;
		}
	}

	socket->write( m_failBlock );
}

void CommandParser::getChannels(ClientSocket *socket, QByteArray &data){
	if( !socket->isAuthorized() ){
		socket->write( m_loginBlock );
		return;
	}
	quint64 id = socket->userId();

	IDatabase *db = qobject_cast<IDatabase*>(Core::instance()->database());

	if( db ){
		QList<ChannelEntry> channels = db->getChannels( id );
		if( channels.size() ){
			socket->write( m_okBlock ); //nadaj ok
			foreach(ChannelEntry entry, channels){ //wysyłaj kolejne kanały
				sendChannel( socket, entry );
			}
		}
	}

	socket->write( m_failBlock );

}

void CommandParser::getNews(ClientSocket *socket, QByteArray &data){
	if( !socket->isAuthorized() ){
		socket->write( m_loginBlock );
		return;
	}

	quint64 id = socket->userId();

	QDataStream inData(data);
	inData.device()->seek( strlen( "GETNEWS\n" ) );
	quint32 channel;
	quint32 timestamp;

	inData >> channel;
	inData >> timestamp;


	IDatabase *db = qobject_cast<IDatabase*>(Core::instance()->database());

	if( db ){
		QList<NewsEntry> news = db->getNews( id, channel, timestamp );
		if( news.size() ){
			socket->write( m_okBlock ); //nadaj ok
			foreach(NewsEntry entry, news){ //wysyłaj kolejne newsy
				sendNews( socket, entry );
			}
		}
	}
	socket->write( m_failBlock );
}

void CommandParser::addChannel(ClientSocket *socket, QByteArray &data){
	if( !socket->isAuthorized() ){
		socket->write( m_loginBlock );
		return;
	}

	quint64 id = socket->userId();

	QTextStream inText(data);

	inText.readLine(); //skip first line

	QString url = inText.readLine();


	IDatabase *db = qobject_cast<IDatabase*>(Core::instance()->database());

	if( db ){
//		bool flag = db->
	}

	socket->write( m_failBlock );

}

void CommandParser::updateNews(ClientSocket *socket, QByteArray &data){
	if( !socket->isAuthorized() ){
		socket->write( m_loginBlock );
		return;
	}

	quint64 id = socket->userId();

	QDataStream inData(data);
	inData.device()->seek( strlen("UPDATENEWS\n") );

	quint32 news, lastOperation;
	inData >> news;
	inData >> lastOperation;

	bool readed, deleted;
	inData >> readed;
	inData >> deleted;

	IDatabase *db = qobject_cast<IDatabase*>(Core::instance()->database());

	if( db ){
		bool flag = db->updateNews(id, news, lastOperation, readed, deleted);
		if( flag ){
			socket->write( m_okBlock );
			return;
		}
	}


	socket->write( m_failBlock );
}

//replays

void CommandParser::sendChannel(ClientSocket* socket,
								const ChannelEntry &entry)
{
	QByteArray replayBlock;

	QDataStream replay(&replayBlock, QIODevice::WriteOnly);
	replay.setVersion(QDataStream::Qt_4_7);
	replay << (quint32)0;
	replay.writeRawData( "TAKECHANNEL\n", strlen("TAKECHANNEL\n") );
	replay << (quint32)entry.id;

	replay.writeRawData( entry.title.toUtf8().constData(),
						 strlen(entry.title.toUtf8().constData()) );
	replay.writeRawData( entry.link.toUtf8().constData(),
						 strlen(entry.link.toUtf8().constData()) );
	replay << entry.desc;

	replay.device()->seek(0);
	replay << (quint32)(replayBlock.size() - sizeof(quint32));

	socket->write(replayBlock);
}

void CommandParser::sendNews(ClientSocket *socket, const NewsEntry &entry){
	QByteArray replayBlock;

	QDataStream replay(&replayBlock, QIODevice::WriteOnly);
	replay.setVersion(QDataStream::Qt_4_7);
	replay << (quint32)0;
	replay.writeRawData( "TAKENEWS\n", strlen("TAKENEWS\n") );
	replay << (quint32)entry.id;
	replay << (quint32)entry.channel;

	replay.writeRawData( entry.title.toUtf8().constData(),
						 strlen(entry.title.toUtf8().constData()) );
	replay.writeRawData( entry.link.toUtf8().constData(),
						 strlen(entry.link.toUtf8().constData()) );
	replay << (quint32)entry.org_size;

	replay << entry.desc;

	replay << (quint32)entry.pubdate;
	replay << (quint32)entry.lastOperation;

	replay << entry.readed;
	replay << entry.deleted;

	replay.device()->seek(0);
	replay << (quint32)(replayBlock.size() - sizeof(quint32));

	socket->write(replayBlock);
}
